﻿using System;
using System.Linq;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace TSharp.Core.Aop
{
    /// <summary>
    /// 拦截器扩展 为每一个配置文件中注册的类型配置默认的拦截器
    /// 
    /// <para>by tangjingbo at 2009-10-27 17:22</para>
    /// </summary>
    public class DefaultInterceptorInterceptionExtension : Interception
    {
        private static readonly IInterceptor[] interceptors;

        static DefaultInterceptorInterceptionExtension()
        {
            interceptors = (from interceptorType in
                                (from type in typeof (IInterceptor).Assembly.GetExportedTypes()
                                 where typeof (IInterceptor).IsAssignableFrom(type) &&
                                       type.IsAbstract == false &&
                                       type.IsInterface == false
                                 select type)
                            select Activator.CreateInstance(interceptorType) as IInterceptor).ToArray();
        }

        /// <summary>
        /// Initial the container with this extension's functionality.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();
            IConfigurationSource configSource = ConfigurationSourceFactory.Create();
            var section = configSource.GetSection(PolicyInjectionSettings.SectionName) as PolicyInjectionSettings;
            if (section != null)
            {
                section.ConfigureContainer(Container, configSource);
            }
            Context.Registering +=
                delegate(Object sender, RegisterEventArgs e) { setInterceptorFor(e.TypeFrom, e.TypeTo, e.Name); };
            Context.RegisteringInstance +=
                delegate(Object sender, RegisterInstanceEventArgs e) { setInterceptorFor(e.RegisteredType, e.Instance.GetType(), e.Name); }
                ;
        }

        private void setInterceptorFor(Type typeToIntercept, Type typeOfInstance, String name)
        {
            foreach (IInterceptor interceptor in interceptors)
            {
                if (interceptor.CanIntercept(typeToIntercept) &&
                    (interceptor.GetInterceptableMethods(typeToIntercept, typeOfInstance).Count() != 0))
                {
                    if (interceptor is IInstanceInterceptor)
                    {
                        Container.Configure<Interception>().SetDefaultInterceptorFor(typeToIntercept,
                                                                                     interceptor as IInstanceInterceptor);
                    }
                    else if (interceptor is ITypeInterceptor)
                    {
                        Container.Configure<Interception>().SetDefaultInterceptorFor(typeToIntercept,
                                                                                     interceptor as ITypeInterceptor);
                    }
                    break;
                }
            }
        }
    }
}